Proposal/teacher onboarding mvp - #595
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Overall, this PR is a solid end-to-end workflow for the teacher invite. Nice work.
Can you add some tests? Given that there are so many status change branches (pending, accepted, rejected, expired), it would be good to have a test that verifies that each status is assigned correctly. You can mock the 3rd party apps (like the SMTP server).
You may also want to add a test to confirm that an uninvited teacher cannot access the classes page.
| "updatedAt" TIMESTAMP(3) NOT NULL, | ||
|
|
||
| CONSTRAINT "StudentInvitation_pkey" PRIMARY KEY ("studentInvitationId") | ||
| ); |
There was a problem hiding this comment.
The StudentInvitation schema changes don't seem like they belong in this PR.
There was a problem hiding this comment.
Good catch — removed. StudentInvitation was leftover from an earlier, separate design for student invites that never shipped (student onboarding ended up going a different route in #600, no invite model at all yet so I am excluding it from here since it can easily be added later based on the teacher onboarding design if we want it). Deleted the model, its relations, and squashed the migrations back into a single initial_setup since we're still pre-release and don't need incremental migration history yet.
| const handleSignIn = async () => { | ||
| await signIn('auth0'); | ||
| }; |
There was a problem hiding this comment.
We are hardcoding auth0 which means a contributor using the Github oAuth would not be able to test this feature locally. I'm not totally opposed to only supporting auth0, but I'm curious, how difficult/complicated would it be to support both auth0 and Github oAuth?
If we do decide to only support auth0, then we should document somewhere in the README that if a developer decides to go with Github oAuth, certain features (like Teacher Invitations) won't work.
There was a problem hiding this comment.
This was a really good catch and I appreciate it. It was hardcoded because the GitHub OAuth has not been functional yet but it was easy to make agnostic. I switched to signIn(null, { callbackUrl: router.asPath }), matching the provider-agnostic pattern already used in components/authButton.js. This respects whichever provider(s) are configured (Auth0 and/or GitHub via GITHUB_OAUTH_PROVIDER_ENABLED), so contributors testing locally with GitHub OAuth aren't blocked on this page anymore, and if the GitHub OAuth is fixed this will already accommodate it.
| - No port conflicts occur because domains are different | ||
| - The port changes in this repository are primarily for local development | ||
|
|
||
| ### Teacher Invitation Email Setup |
There was a problem hiding this comment.
The documentation is great, but I'm concerned the README.md is getting too long. Can you create a subpage for this documentation and link it from the README?
…cceptance page, tests)
…ity signature
- Convert pages/error.js and pages/teacher/invite/[inviteToken].js to modern Next.js Link pattern (no nested anchors)
- Refactor util/inviteEmail.js to accept object params {invitedTeacherEmail, inviteUrl, expiresAt, invitedByEmail}
- Ensures proper Nodemailer integration for teacher invitation emails
- redesign invite acceptance page with FCC-aligned styling - update teacher invitation email content and branding hierarchy - fix teacher invite post-accept redirect by role - improve revoke API message for inactive invites - add README testing/setup notes for SMTP invite flow
…tion The StudentInvitation model/relations were leftover scaffolding from an earlier, superseded student-invite design and had no consumers anywhere in this branch (student onboarding shipped via a different, join-link based flow in freeCodeCamp#600). Per review feedback, they don't belong in the teacher invitation PR. Also collapsed the two migrations back into a single initial_setup migration, regenerated via `prisma migrate dev` against a local dev database, since the project is still pre-release and doesn't need incremental migration history yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
signIn('auth0') skipped NextAuth's provider selection and always
launched Auth0's flow, even for contributors running locally with
GITHUB_OAUTH_PROVIDER_ENABLED=true and no Auth0 credentials. Switch to
signIn(null, { callbackUrl }), matching the provider-agnostic pattern
already used in components/authButton.js, and keep the user on the
invite-accept page after sign-in instead of redirecting to '/'.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds tests for pages/api/teacher_invites/accept.js,
pages/api/admin/teacher_invites/{resend,revoke}.js covering each status
branch (PENDING valid/expired, already ACCEPTED by self/other, and
REVOKED/CANCELLED/EXPIRED rejection), per review feedback asking for
coverage of each invitation status. Prisma, next-auth's session lookup,
and outbound email are all mocked - no real database or SMTP calls.
Also documents current role-promotion behavior on accept: ADMIN is
protected and stays ADMIN, while TEACHER/STUDENT/NONE are all
unconditionally promoted to TEACHER (single-role field, no student
guard needed since classroom membership is just a roster entry).
Adds direct unit tests for areEquivalentInviteEmails' Gmail-style
email normalization (dot/plus stripping), previously untested.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fca2eec to
a80a4c4
Compare
pages/classes/index.js's getServerSideProps gate only checks a user's current role - it has no notion of invitation history. That single check is what covers every way an account can lack teacher access: never invited, a teacher invite that was revoked or left to expire before being accepted, or being demoted/removed after previously being a teacher. Covers that gate: no session and non-TEACHER role both redirect to /error, ADMIN redirects to /admin, and only an accepted TEACHER reaches the page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
I added test coverage for both asks:
All mocked (Prisma, session, email) — no real DB/SMTP in the test run. Hi @utsab it's ready for a re-review when you are available! |
Checklist:
Update index.md)This PR is not associated with a specific issue
Case Study (Teacher Invite Acceptance Flow)
/teacher/invite/<token>.ACCEPTEDand user role is set toTEACHER.What Changed (and Why)
Teacher invite backend APIs to support create/list/resend/revoke and secure acceptance.
Reason: completes the core onboarding lifecycle with role-safe state transitions.
Files:
pages/api/admin/teacher_invites/create.js
pages/api/admin/teacher_invites/list.js
pages/api/admin/teacher_invites/resend.js
pages/api/admin/teacher_invites/revoke.js
pages/api/teacher_invites/accept.js
util/inviteApiUtils.js
Email delivery + feature flag rollout support.
Reason: enables controlled rollout and real invitation delivery.
Files:
util/inviteEmail.js
util/featureFlags.js
package.json
package-lock.json
Admin + teacher UI flow.
Reason: gives a usable end-to-end path from invite creation to invite acceptance.
Files:
components/TeacherInvitesPanel.js
components/TeacherInvitesPanel.module.css
pages/admin/index.js
pages/teacher/invite/[inviteToken].js
styles/Home.module.css
pages/error.js
Data model + migration for invitation lifecycle.
Reason: persists invitation state and supports expiry/revoke/accept transitions.
Files:
prisma/schema.prisma
prisma/migrations/20260409192210_add_invitation_models/migration.sql
Env/security/docs updates.
Reason: prevent future secret leaks and keep setup clear with tracked templates.
Files:
.gitignore
.env.sample
.env.development.example
.env.production.example
README.md
.env.development/.env.productionremoved from trackingValidation
npm run lint:codenpm testHow to Test
Prerequisites
This branch allows you to create an
ADMINaccount and send out email invitations to users to onboard as teachers.You need:
Configuring this branch for local development
CarlyAThomas:proposal/teacher-onboarding-mvpbranch.cp .env.development.example .env.developmentSMTP_USERin.env.developmentwith your Admin Email.SMTP_PASSin.env.developmentwith the new password.Running the app
npx prisma migrate reset, and pressyto reset your database.npm run developandnpx prisma studioto run the project.ADMIN.Testing